<?php

// +----------------------------------------------------------------------
// |ZBPHP[基于ThinkPHP5.1开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2016-2019 http://www.benbenwangluo.com
// +----------------------------------------------------------------------
// | Author 似水星辰 [ 2630481389@qq.com ]
// +----------------------------------------------------------------------
// | 中犇软件 技术六部 出品
// +----------------------------------------------------------------------
namespace app\customer\model;

use think\Model;

/**
 * 聊天记录
 * @author 晓风<215628355@qq.com>
 * @date 2021-5-26 9:19:54
 */
class Chat extends Model {

    // 设置当前模型对应的完整数据表名称
    protected $table = '__CUSTOMER_CHAT__';
    // 自动写入时间戳
    protected $autoWriteTimestamp = true;
    //设置主键
    protected $pk = "aid";

   public static $types = [
        0 =>"内容",
        1 =>"图片",
        2 =>"视频",
        3 => "商品",
        4 => "订单",
    ];

    /**
     * 获取文档列表
     * @param mixed $map 筛选条件
     * @param mixed $order 排序
     * @return mixed
     * @author 晓风<215628355@qq.com>
     */
    public static function getList($map = [], $order = []) {
        return self::where($map)
                        ->order($order)
                        ->paginate();
    }
    /**
     * 过滤并检测然后返回普通聊天文字内容
     * @author 晓风<215628355@qq.com>
     * @param string $content
     * @return string
     * @throws \Exception
     */
    public static function trimText($content){     
        if(mb_strlen($content) > 200){
            throw new \Exception("聊天内容太长了",2001);
        }
        $content = self::htmltotxt($content);
        if(!$content){
             throw new \Exception("聊天内容不合法",2002);
        }
        return $content;
    }
     /**
     * 过滤并检测然后返回视频和图片连接内容
     * @author 晓风<215628355@qq.com>
     * @param string $content
     * @return string
     * @throws \Exception
     */
    public static function trimLink($content){
        if (filter_var($content, FILTER_VALIDATE_URL) !== false) {
            return $content;
        }
        throw new \Exception("视频或图片需要为超链接地址",3001);
    }
    
    /**
     * 过滤并检测然后返回json内容
     * @author 晓风<215628355@qq.com>
     * @param string $content
     * @param int $type
     * @return string
     * @throws \Exception
     */
    public static function trimJson($content){
        if(!is_array(json_decode($content,true))){
            throw new \Exception("发送内容必须为json",4001);
        }       
        return $content;
    }
      /**
     * 过滤并检测然后返回商品内容
     * @author 晓风<215628355@qq.com>
     * @param string $content
     * @return string
     * @throws \Exception
     */
    public static function trimGoods($content){
        $param = json_decode($content,true);
        if(!is_array($param)){
            throw new \Exception("发送内容必须为json",6001);
        }     
        if(empty($param["goods_id"])){
            throw new \Exception("商品类型缺少goods_id",6002);
        }
        $param["sku_id"] = $param["sku_id"] ?? 0;
        $goods = self::getGoodsInfo($param["goods_id"],$param["sku_id"]);
        if(!$goods){
            throw new \Exception("未找到此商品",6003);
        }
        return json_encode($goods['content']);
    }
      /**
     * 过滤并检测然后返回订单内容
     * @author 晓风<215628355@qq.com>
     * @param string $content
     * @return string
     * @throws \Exception
     */
    public static function trimOrder($content){
        $param = json_decode($content,true);
        if(!is_array($param)){
            throw new \Exception("发送内容必须为json",7001);
        }            
        if(empty($param["order_sn"])){
            throw new \Exception("订单类型缺少order_sn",7002);
        }          
        $order = self::getOrderInfo($param["order_sn"]);
        if(!$order){
            throw new \Exception("未找到此订单",7003);
        }
        return json_encode($order["content"]);
    }
    /**
     * 获得消息类型的会话标题和检测消息内容
     * @author 晓风<215628355@qq.com>
     * @param int $type
     * @param string $content
     * @param string $sessionTitle
     * @return type
     */
    public static function getSessionTitleAndContent(int $type,string $content , string $sessionTitle = ""){
        $new = $content;
        switch($type){
            case 0 :
                $content = $new = self::trimText($content);
                break;
            case 1:
                $new = "[图片]";
                $content =  self::trimLink($content);                
                break;            
            case 2:
                $new = "[视频]";
                $content =  self::trimLink($content);                
                break;
            case 3:
                $new = "[商品]";
                $content =  self::trimGoods($content);  
                break;
            case 4:
                $new = "[订单]";
                $content =  self::trimOrder($content);  
                break;
            default :
                $new =  $sessionTitle ? "[".$sessionTitle."]" : "[消息]";
                $content =  self::trimJson($content);                  
                break;
        } 
        return [
            "session_title"=>$new,
            "content"=>$content
        ];
    }
    /**
     * SnowFlake 算法简单实现
     * @author 晓风<215628355@qq.com>
     * @param int $machineId
     * @return string
     */
    public static function getMsgId(int $machineId = null) {
        $time = floor(microtime(true) * 1000);
        $time -=  1479533469598;  
        $base = decbin(1099511627775 + $time);      
        if($machineId) {      
            $machineId = str_pad(decbin($machineId), 10, "0", STR_PAD_LEFT);
        }
        $random = str_pad(decbin(mt_rand(0,  4095)), 12, "0", STR_PAD_LEFT);
        $base = $base.$machineId.$random;     
        return bindec($base);
    }
    /**
     * 添加聊天记录-该方法仅限用户给客服发消息
     * @author 晓风<215628355@qq.com>
     * @param int $store_id 店铺ID
     * @param int $user_id 发件人ID   
     * @param int $type 内容的类型 0 文字 1图片 2视频
     * @param string $content 内容     
     * @return self
     * @throws \Exception
     */    
    public static function addUserMessageInfo(int $store_id,int $user_id ,int $type,string $content ,string $sessionTitle = ""  ){        
        //检查店铺
        $store = Shop::where("store_id",$store_id)->field("store_id,store_name,store_logo,member_id")->where("status",1)->find();
        if(!$store){
            throw new \Exception("未找到该店铺",1000);
        }
        $action = self::getSessionTitleAndContent($type, $content , $sessionTitle);
        $new = $action["session_title"];
        $content = $action["content"];
        //写入消息会话
        $session = Session::addInfo($store,$user_id,$user_id,$new,1);   
        $msgid = self::getMsgId($user_id);
        $data = [
            "store_id"=> $store["store_id"],
            "msgid"=>$msgid,
            "user_id"=>$session["user_id"],
            "service_user_id"=>$session["service_user_id"],
            "type"=>$type,          
            "content"=>$content,
            "form_type"=>1,
            "create_time"=>time()
        ];
        $Res =  self::create($data);
        if(!$Res){
            throw new \Exception("保存失败",1001);
        }  
        $data["session_title"] = $new;
        $data["store_name"] = $store["store_name"];
        $data["store_logo"] = $store["store_logo"];
        return $data;
    }
    
    /**
     * 添加聊天记录-该方法仅限客服给用户发消息
     * @author 晓风<215628355@qq.com>
     * @param int $store_id 店铺ID
     * @param int $user_id 发件人ID   
     * @param int $to_user_id 客户ID   
     * @param int $type 内容的类型 0 文字 1图片 2视频
     * @param string $content 内容       
     * @return self
     * @throws \Exception
     */    
    public static function addServiceMessageInfo(int $store_id,int $user_id ,int $to_user_id,int $type,string $content ,string $sessionTitle = "" ){        
        //检查店铺
        $store = Shop::where("store_id",$store_id)->field("store_id,store_name,store_logo,member_id")->where("status",1)->find();
        if(!$store){
            throw new \Exception("未找到该店铺",1000);
        }
        $action = self::getSessionTitleAndContent($type, $content , $sessionTitle);
        $new = $action["session_title"];
        $content = $action["content"];          
        //写入消息会话
        $session = Session::addInfo($store,$user_id,$to_user_id,$new,2);   
        $msgid =   self::getMsgId($user_id);
        $data = [
            "store_id"=> $store["store_id"],
            "msgid"=>$msgid,
            "user_id"=>$session["user_id"],
            "service_user_id"=>$session["service_user_id"],
            "type"=>$type,          
            "content"=>$content,
            "form_type"=>2,
            "create_time"=>time()
        ];
        $Res =  self::create($data);
        if(!$Res){
            throw new \Exception("保存失败",1001);
        }  
        $data["session_title"] = $new;
        $data["store_name"] = $store["store_name"];
        $data["store_logo"] = $store["store_logo"];
        return $data;
    }

    
    /**
     * 转为普通文字内容
     * @param string $string
     * @return string
     */
     public static function htmltotxt($string) {
        $string = htmlspecialchars_decode($string); //先 反转为正常html
        $string = str_replace('"', '＂', $string);
        $string = str_replace("'", '＇', $string);
        $string = htmlspecialchars(strip_tags($string));
        return  $string;//\util\Functions::killWord($string);
    }
    

    /**
     * 获得用户与店铺之间的聊天记录
     * @author 晓风<215628355@qq.com>
     * @param int $user_id 我的会员ID
     * @param int $store_id 店铺ID
     * @param int $service_user_id 或指定客服ID（客服端用到）
     * @param string $msgid 最新消息ID
     * @param int $size 长度
     * @return array
     */
    public static function getUserStoreMsgList(int $user_id,int $store_id,int $service_user_id = 0,string $msgid = "",int $size = 10){
          $map = [];
          if($msgid){
              $aid = self::where("msgid",$msgid)->value("aid");
              $map[] = ["aid","<",$aid];
          }
          if($service_user_id > 0){
              $map[] = ["service_user_id","in",[0,$service_user_id]];
          }
          return self::where("user_id",$user_id)                
                ->where("store_id",$store_id)
                ->where($map)
                ->limit($size)
                ->order("aid desc")
                ->select();
    }  
    /**
     * 删除聊天记录
     * @author 晓风<215628355@qq.com>
     * @param int $user_id 发件人ID
     * @param int $store_id 店铺ID 
     * @param bool $delete 删除方式 true 物理删除  false 标记删除
     */
    public static function delMsg(int $user_id ,int $store_id,bool $delete  = false){
       
        
        return true;
    }
    /**
     * 撤回消息
     * @author 晓风<215628355@qq.com>
     * @param int $user_id 会员ID
     * @param string $msgid 消息ID
     * @return boolean
     * @throws \Exception
     */
    public static function recallMessage( int $user_id,string $msgid){
        $ret = self::where("msgid",$msgid)->where("user_id",$user_id)->find();
        if(!$ret){
            throw new \Exception("删除失败");
        }
        self::where("aid",$ret["aid"])->delete();    
        $time = time();
        Session::where("user_id",$user_id)->where("store_id", $ret["store_id"])->update([
            "update_time"=>$time,
            "content"=>"[消息已撤回]"
        ]);      
        return true;
    }
    /**
     * IM登录票据
     * 10分钟内有效
     * @author 晓风<215628355@qq.com>
     * @param int $user_id
     * @return string
     */    
    public static function getUserSig(int $user_id){        
        $redis = \app\common\model\Redis::handler();
        $rand = self::getMsgId();
        $token = md5($user_id . "- ". time() . "-" .$rand);
        $redis->setex("ST_" . $token,600,$user_id);     
        $socket_url = \app\admin\model\Module::getConfig('customer',"socket_url");
        $wss_socket_url = \app\admin\model\Module::getConfig("customer","wss_socket_url");
  
        return [
            "userSig"=>$token,          
            "uid"=>$user_id,
            "socket_url"=>$socket_url,
            "wss_socket_url"=>$wss_socket_url
        ];
    }
  
     /**
     * h5版唤醒链接生成
     * 10分钟内有效
     * @author 晓风<215628355@qq.com>
     * @param int $user_id
     * @return string
     */    
    public static function getChatUrl(int $user_id ,int $store_id ,array $query = []){   
        $shop = Shop::where("store_id",$store_id)->where("status",1)->find();
        if(!$shop){
            throw new \Exception("店铺未注册");
        }        
        $redis = \app\common\model\Redis::handler();
        $rand = self::getMsgId();
        $token = md5($user_id . "- ". time() . "-" .$rand);
        $redis->setex("CT_" . $token,600,json_encode([
            "user_id"=>$user_id,
            "store_id"=>$store_id
        ]));     
        $shop["chat_url"] = config("web_site_domain") . "/index.php/customer/chat_login/index?token=".$token . ($query ? '&'.http_build_query($query) : "");
        return $shop;
    }
    
        /**
     * h5版唤醒链接生成
     * 10分钟内有效
     * @author 晓风<215628355@qq.com>
     * @param int $user_id
     * @return string
     */    
    public static function getServiceUrl(int $user_id ,int $store_id = 0 ,array $query = []){   
        
        $map[] = ["member_id","=",$user_id];
        if($store_id){
            $map[] = ["store_id","=",$store_id];
        }        
        $check = Customer::where($map)->count();
        if($check <=0){
            throw new \Exception($store_id ? "您还不是该店铺的客服" : "您还未注册客服系统");
        }        
        $redis = \app\common\model\Redis::handler();
        $rand = self::getMsgId();
        $token = md5($user_id . "- ". time() . "-" .$rand);
        $redis->setex("ST_" . $token,600,json_encode([
            "user_id"=>$user_id,
            "store_id"=>$store_id
        ]));     
        $shop["chat_url"] = config("web_site_domain") . "/index.php/customer/login/mlogin?token=".$token;
        return $shop;
    }
    /**
     * 获取发送商品的content
     * @author 晓风<215628355@qq.com>
     */
    public static function getGoodsInfo($goods_id,$sku_id = 0){
  
        $goods = \app\goods\model\Goods::where("id",$goods_id)->field("id as goods_id,name,thumb,shop_price as price")->find();

        if($goods){          
            if($sku_id){
                $sku = \app\goods\model\GoodsSku::where('goods_id',$goods_id)->where("sku_id",$sku_id)->field("key_name,shop_price as price,spec_img")->find();
            }else{
                $sku = false;
            }
            $goods["sku"] = $sku ? $sku["key_name"] : "";
            $goods["price"] = $sku ? $sku["price"] :  $goods["price"];
            $goods["thumb"] = get_file_url(empty($sku["spec_img"]) ?   $goods["thumb"] :  $sku["spec_img"]);
        }       
        $goods["sku_id"] = $sku_id;
        return $goods ? [
            "type"=>3,
            "content"=>$goods
        ] : null;
    }
    
     /**
     * 获取发送订单的content
     * @author 晓风<215628355@qq.com>
     */
    public static function getOrderInfo($order_sn){
        $order = \app\common\model\Order::where("order_sn",$order_sn)->field("order_sn,payable_money,status")->find();
        if($order){          
            $order['status'] = \app\common\model\Order::$order_status[ $order['status'] ];
            $goods= \app\order\model\OrderGoods::where("order_sn",$order_sn)->field("goods_id,goods_name,sku_name,goods_thumb,num,goods_money")->select();
            foreach($goods as &$good){
                $good["goods_thumb"] = get_file_url($good["goods_thumb"]);
                $good["sku_name"] =  $good["sku_name"] ?: "";
            }
            $order["goods"] = $goods;    
            $order["info"] = \app\order\model\OrderInfo::where("order_sn",$order_sn)->field("receiver_name,receiver_mobile,province,city,district,receiver_address,remark")->find();
        }       
        return $order ? [
            "type"=>4,
            "content"=>$order
        ] : null;
    }

}
